﻿using Microsoft.Xna.Framework;

namespace ProcessManagerXNA.Process
{
    public enum ProcessState
    {
        //Processes that are neither dade or alive
        UNINITILIZED,
        REMOVED,

        // Living Processes
        RUNNING,
        PAUSED,

        //Dead Processes
        SUCCEEDED,
        FAILED,
        ABORTED
    }

    public interface IProcess
    {
        void Succeed();
        void Fail();
        void Abort();

        ProcessState GetState();
        bool IsAlive();
        bool IsDead();
        bool IsRemoved();
        bool IsPaused();

        void Pause();
        void Resume();

        void OnInit();
        void OnUpdate(GameTime gameTime);
        void OnSuccess();
        void OnFail();
        void OnAbort();

        void AttachChild(IProcess process);
        IProcess GetChild();
        IProcess RemoveChild();
    }

    public abstract class BaseProcess : IProcess
    {
        private IProcess m_child;
        private ProcessState m_state;

        protected BaseProcess()
        {
            m_state = ProcessState.UNINITILIZED;
        }

        ~BaseProcess()
        {
            if (m_child != null) m_child.OnAbort();
        }

        public void Succeed() { m_state = ProcessState.SUCCEEDED; }
        public void Fail() { m_state = ProcessState.FAILED; }
        public void Abort() { m_state = ProcessState.ABORTED; }

        public virtual void OnInit() { m_state = ProcessState.RUNNING; }
        public abstract void OnUpdate(GameTime gameTime);
        public abstract void OnSuccess();
        public abstract void OnFail();
        public abstract void OnAbort();

        public void Pause() { if (m_state == ProcessState.RUNNING) m_state = ProcessState.PAUSED; }
        public void Resume() { if (m_state == ProcessState.PAUSED) m_state = ProcessState.RUNNING; }

        public ProcessState GetState() { return m_state; }
        public bool IsAlive() { return (m_state == ProcessState.RUNNING || m_state == ProcessState.PAUSED); }
        public bool IsDead() { return (m_state == ProcessState.SUCCEEDED || m_state == ProcessState.FAILED || m_state == ProcessState.ABORTED); }
        public bool IsRemoved() { return (m_state == ProcessState.REMOVED); }
        public bool IsPaused() { return m_state == ProcessState.PAUSED; }

        public void AttachChild(IProcess process)
        {
            if (m_child != null)
                m_child.AttachChild(process);
            else
                m_child = process;
        }

        public IProcess RemoveChild()
        {
            if (m_child != null)
            {
                IProcess child = m_child;
                m_child = null;

                return child;
            }
            return null;
        }

        public IProcess GetChild() { return m_child; }
    }
}
